package cmd

import (
	"bytes"
	"dpm/internal/config"
	"dpm/pkg/tools"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"gopkg.in/yaml.v3"
)

// CompileAndBuild 编译并构建应用程序
//
// buildConfig: 构建配置
//
// 返回值: 错误信息
func CompileAndBuild(buildConfig config.Config) error {
	// 打印构建信息
	cl.Greenf("[开始构建] %s %s \360\237\216\210 \n", buildConfig.Build.Name, buildConfig.Build.Version)

	// 检查当前平台系统和架构是否符合构建要求
	if err := tools.CheckOSAndArch(buildConfig.Build.Platform, buildConfig.Build.Name); err != nil {
		return err
	}

	// 检查项目名称是否为空
	if buildConfig.Build.Name == "" {
		return errors.New("项目名称不能为空")
	}

	// 检查项目版本是否为空
	if buildConfig.Build.Version == "" {
		return errors.New("项目版本不能为空")
	}

	// 设置环境变量
	if err := tools.SetupEnv(buildConfig.Build.Environment); err != nil {
		return err
	}

	// 获取项目根目录
	var mainPath string
	if buildConfig.Build.MainPath == "" {
		return fmt.Errorf("项目根目录配置 main_Path 不能为空, 请检查配置文件")
	}

	// 如果是绝对路径, 则直接使用
	if filepath.IsAbs(buildConfig.Build.MainPath) {
		mainPath = buildConfig.Build.MainPath
	} else {
		// 如果是相对路径, 则转换为绝对路径
		if tempPath, err := filepath.Abs(buildConfig.Build.MainPath); err != nil {
			return fmt.Errorf("获取项目根目录失败: %s", err)
		} else {
			mainPath = tempPath
		}
	}

	// 检查项目根目录是否存在
	if _, err := tools.CheckPath(mainPath); err != nil {
		return fmt.Errorf("项目根目录不存在: %s", buildConfig.Build.MainPath)
	}

	// 获取入口文件路径
	entryPath := buildConfig.Build.EntryPath // 入口文件路径

	// 获取输出目录
	var outputDir string
	if buildConfig.Build.OutputDir == "" {
		return fmt.Errorf("输出目录 output_dir 不能为空, 请配置为: [output|dist|...]")
	}
	if filepath.IsAbs(buildConfig.Build.OutputDir) {
		return fmt.Errorf("输出目录不能是绝对路径: %s", buildConfig.Build.OutputDir)
	}

	// 获取输出目录，项目根目录 + 输出目录
	outputDir = filepath.Join(mainPath, buildConfig.Build.OutputDir)
	// 检查输出目录是否存在，如果不存在则创建
	if err := tools.CheckAndCreateDir(outputDir, true); err != nil {
		return err
	}

	// 检查入口文件是否存在
	if entryPath == "" {
		entryPath = "./main.go" // 如果未指定入口文件，则使用默认的 ./main.go 文件
	}
	if _, err := tools.CheckPath(entryPath); err != nil {
		return fmt.Errorf("入口文件不存在: %s", entryPath)
	}

	// 检查构建目标平台是否是支持的
	for _, target := range buildConfig.Build.Targets {
		// 检查目标平台系统是否支持
		if err := tools.ValidateTarget(target); err != nil {
			return err
		}
	}

	// 如果配置了 GOROOT, 则使用检查GOROOT 是否存在
	if buildConfig.Build.GORoot != "" {
		// 调用 checkAndCreateDir 函数检查
		if err := tools.CheckAndCreateDir(buildConfig.Build.GORoot, false); err != nil {
			return fmt.Errorf("GORoot 目录不存在: %s", buildConfig.Build.GORoot)
		}
	}

	// 如果配置了 GORoot, 则使用检查 GORoot 是否符合要求
	var GORoot string
	if buildConfig.Build.GORoot != "" {
		// 去除右侧的分割符
		GORoot = strings.TrimSuffix(buildConfig.Build.GORoot, string(os.PathSeparator))

		// 检查右侧是否是bin结尾
		if strings.HasSuffix(GORoot, "bin") {
			return fmt.Errorf("GORoot 目录不用以 bin 结尾: %s, 例如: /usr/local/go", buildConfig.Build.GORoot)
		}

		// 检查 GORoot 是否为GO编译器的安装目录
		if _, err := tools.CheckPath(filepath.Join(GORoot, "bin", "go")); err != nil {
			return fmt.Errorf("GORoot 目录不是 GO 编译器的安装目录: %s", buildConfig.Build.GORoot)
		}
	} else {
		// 如果没有配置 GORoot, 则使用默认的 GORoot
		if tempGORoot, ok := os.LookupEnv("GOROOT"); ok {
			GORoot = tempGORoot
		} else {
			return fmt.Errorf("GORoot 环境变量不存在, 请先设置 GOROOT 环境变量")
		}
	}

	// 切换到项目根目录
	if err := os.Chdir(mainPath); err != nil {
		return fmt.Errorf("切换到源代码目录失败: %s", err)
	} else {
		cl.Green("[工作目录]")
		cl.Greenf("- 当前目录: %s\n", mainPath)
	}

	// 构建命令
	var buildCmd string
	// 构建文件名
	var buildFileName string
	// 拼接的文件名
	var outputFileName string

	// 拼接构建命令, 如果配置了 GORoot, 则使用配置的 GORoot, 否则使用默认的 GOROOT 环境变量
	buildCmd = filepath.Join(GORoot, "bin", "go")

	// 检查构建命令是否存在
	if runtime.GOOS == "windows" {
		tempBuildCmd := fmt.Sprint(buildCmd, ".exe")
		if _, err := tools.CheckPath(tempBuildCmd); err != nil {
			return fmt.Errorf("构建命令不存在: %s", tempBuildCmd)
		}
	} else {
		if _, err := tools.CheckPath(buildCmd); err != nil {
			return fmt.Errorf("构建命令不存在: %s", buildCmd)
		}
	}

	// 依赖管理
	cl.Green("[依赖管理]")

	// 检查项目根目录是否存在 go.mod 文件
	if _, err := tools.CheckPath(filepath.Join(mainPath, "go.mod")); err != nil {
		return fmt.Errorf("项目根目录不存在 go.mod 文件: %s, 请先执行 go mod init <module name>", mainPath)
	}

	// 创建构建命令, 格式为: go mod tidy
	depCmd := exec.Command(buildCmd, "mod", "tidy")

	// 设置标准输出和错误输出
	var stdout, stderr bytes.Buffer
	depCmd.Stdout = &stdout
	depCmd.Stderr = &stderr

	if err := depCmd.Run(); err != nil {
		return fmt.Errorf("依赖管理失败: %s", err)
	}

	// 处理标准输出
	if outputStdout, err := tools.DecodeBytes(stdout.Bytes()); err != nil {
		cl.Redf("解码标准输出失败: %v\n", err)
	} else if outputStdout != "" {
		fmt.Println(outputStdout)
	}

	// 处理标准错误
	if outputStderr, err := tools.DecodeBytes(stderr.Bytes()); err != nil {
		cl.Redf("解码标准错误失败: %v\n", err)
	} else if outputStderr != "" {
		fmt.Println(outputStderr)
	}

	cl.Greenf("- 依赖管理完成 \342\234\224 \n")

	// 如果配置了注入 git 信息, 则注入 git 信息
	var gitVersion string    // 版本信息
	var gitCommit string     // commit 信息
	var gitCommitTime string // commit 时间
	var buildTime string     // 构建时间
	var gitTreeState string  // git 仓库状态
	if *isGitInjected {
		// 注入 git 信息
		cl.Green("[注入 git 信息]")

		// 设置err变量
		var err error

		// 检查项目根目录是否存在 pkg/version包
		if _, err := tools.CheckPath(filepath.Join(mainPath, "pkg", "version")); err != nil {
			return fmt.Errorf("项目根目录不存在 pkg/version 包: %s, 请先执行 dpm init -type version", mainPath)
		}

		// 获取 git 版本信息
		gitVersion, err = tools.GetGitVersion()
		if err != nil {
			return err
		}

		// 获取 git commit 信息
		gitCommit, err = tools.GetGitCommit()
		if err != nil {
			return err
		}

		// 获取 build time 信息
		buildTime, err = tools.GetBuildTime()
		if err != nil {
			return err
		}

		// 获取 git commit 时间
		gitCommitTime, err = tools.GetGitCommitTime()
		if err != nil {
			return err
		}

		// 获取 git 仓库状态
		gitTreeState, err = tools.GetGitTreeState()
		if err != nil {
			return err
		}

		// 打印注入的 git 信息
		cl.Greenf("%-8s %-10s", "- 版本信息:", gitVersion)
		cl.Greenf("%-8s %-10s", "- 提交哈希:", gitCommit)
		cl.Greenf("%-8s %-10s", "- 提交时间:", gitCommitTime)
		cl.Greenf("%-8s %-10s", "- 构建时间:", buildTime)
		cl.Greenf("%-8s %-10s", "- 仓库状态:", gitTreeState)
		println()
	}

	// 打印提示信息
	cl.Green("[构建输出]")
	cl.Greenf("- 构建输出目录: %s", outputDir)

	// 获取本次构建总数
	buildCount := len(buildConfig.Build.Targets)

	// 定义一个计数器
	jd := 1

	// 处理项目名称, 只获取最后一个 / 后面的内容
	var projectName string
	if strings.Contains(buildConfig.Build.Name, "/") { // 如果包含 /, 则获取最后一个 / 后面的内容
		projectName = strings.Split(buildConfig.Build.Name, "/")[len(strings.Split(buildConfig.Build.Name, "/"))-1]
	} else { // 如果不包含 /, 则直接使用项目名称
		projectName = buildConfig.Build.Name
	}

	// 定义一个切片, 用于存储需要压缩的文件
	var fileSliceToCompress []string

	// 遍历构建目标平台
	for _, target := range buildConfig.Build.Targets {
		// 如果配置了输出文件名, 则使用配置的输出文件名, 否则使用默认的: 项目名称+目标平台系统+目标平台架构
		if target.OutputName != "" {
			// 获取输出目录的绝对路径
			outputDirAbs, err := filepath.Abs(outputDir)
			if err != nil {
				return fmt.Errorf("获取输出目录绝对路径失败: %s", err)
			}

			// 如果输出文件名已经包含了后缀, 则直接使用输出文件名
			if strings.HasSuffix(target.OutputName, ".exe") {
				outputFileName = target.OutputName

				// 如果输出文件名没有包含后缀, 则根据目标平台系统添加后缀
			} else if strings.ToLower(target.OS) == "windows" {
				outputFileName = fmt.Sprintf("%s.exe", target.OutputName)
			} else {
				outputFileName = target.OutputName // 如果输出文件名没有包含后缀, 则直接使用输出文件名
			}

			// 构建文件名: 输出目录/输出文件名
			buildFileName = filepath.Join(outputDirAbs, outputFileName)
		} else {
			// 获取输出目录的绝对路径
			outputDirAbs, err := filepath.Abs(outputDir)
			if err != nil {
				return fmt.Errorf("获取输出目录绝对路径失败: %s", err)
			}

			// 如果输出文件名没有包含后缀, 则根据目标平台系统添加后缀
			if strings.ToLower(target.OS) == "windows" {
				outputFileName = fmt.Sprintf("%s-%s-%s-%s.exe", projectName, target.OS, target.Arch, buildConfig.Build.Version)
			} else {
				outputFileName = fmt.Sprintf("%s-%s-%s-%s", projectName, target.OS, target.Arch, buildConfig.Build.Version)
			}

			// 如果没有指定输出文件名, 则使用默认项目名称拼接输出文件名
			// 构建文件名: 项目名称-目标平台系统-目标平台架构
			buildFileName = filepath.Join(outputDirAbs, outputFileName)
		}

		// 创建构建命令, 格式为: go build -o 输出文件名 入口文件路径
		var cmd *exec.Cmd
		if *isGitInjected {
			// 如果配置了注入 git 信息, 则注入 git 信息
			ldflagsCmd := fmt.Sprintf("-X '%s/pkg/version.appName=%s' -X '%s/pkg/version.gitVersion=%s' -X '%s/pkg/version.gitCommit=%s' -X '%s/pkg/version.gitCommitTime=%s' -X '%s/pkg/version.gitTreeState=%s' -X '%s/pkg/version.buildTime=%s' -s -w", buildConfig.Build.Name, buildConfig.Build.Name, buildConfig.Build.Name, gitVersion, buildConfig.Build.Name, gitCommit, buildConfig.Build.Name, gitCommitTime, buildConfig.Build.Name, gitTreeState, buildConfig.Build.Name, buildTime)
			cmd = exec.Command(buildCmd, "build", "-o", buildFileName, "-ldflags", ldflagsCmd, entryPath)
		} else {
			// 如果没有配置注入 git 信息, 则不注入 git 信息
			cmd = exec.Command(buildCmd, "build", "-o", buildFileName, "-ldflags", "-s -w", entryPath)
		}

		// 设置标准输出和错误输出
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		// 设置目标平台系统和架构
		GOOS := fmt.Sprintf("GOOS=%s", target.OS)
		GOARCH := fmt.Sprintf("GOARCH=%s", target.Arch)

		// 设置环境变量, 将当前进程的环境变量和目标平台系统和架构添加到构建命令的环境变量中
		cmd.Env = append(os.Environ(), GOOS, GOARCH)

		// 执行构建命令
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("构建 %s 失败: %s", outputFileName, err)
		} else {
			// 添加构建文件到切片中, 用于压缩
			fileSliceToCompress = append(fileSliceToCompress, buildFileName)

			// 打印构建成功信息
			cl.Greenf("%d/%d: 构建 %s 成功 \342\234\224 -> %s", jd, buildCount, outputFileName, buildFileName)
		}

		// 计数器自增
		jd++
	}
	// 保持一个空行
	println()

	// 压缩构建文件
	if *isPackageZip {
		// 定义计数器
		jdz := 1

		// 打印提示信息
		cl.Green("[打包构建文件]")
		// 检查输出目录是否存在
		if _, err := tools.CheckPath(outputDir); err != nil {
			return fmt.Errorf("输出目录不存在: %s", outputDir)
		}

		if err := os.Chdir(outputDir); err != nil {
			return fmt.Errorf("切换到输出目录失败: %s", err)
		}
		cl.Greenf("- 打包输出目录: %s", outputDir)

		// 遍历切片, 打包构建文件
		for _, file := range fileSliceToCompress {
			// 获取打包前的文件名
			fileName := filepath.Base(file)
			// 获取打包后的文件名
			fileNameAfter := fmt.Sprint(fileName, ".zip")

			// 开始打包
			if err := tools.CreateZip(fileName, fileNameAfter); err != nil {
				return fmt.Errorf("压缩文件失败: %s", err)
			}
			cl.Greenf("%d/%d: 打包 %s \342\234\224 -> %s", jdz, buildCount, fileName, filepath.Join(outputDir, fileNameAfter))

			// 删除原文件
			if err := os.Remove(file); err != nil {
				return fmt.Errorf("清理源文件失败: %s", err)
			}
			// 计数器自增
			jdz++
		}

		// 保持一个空行
		println()
	}

	// 打印构建完成信息, 打印一个火箭
	cl.Greenf("[构建完成] %s %s \360\237\216\211", buildConfig.Build.Name, buildConfig.Build.Version)

	return nil
}

// initMakeself 初始化makefile自解压脚本
func initMakeself(path string) error {
	// 打印提示信息
	cl.PrintSuccess("准备初始化makeself...")

	// 获取makeself.sh文件路径
	makeSelfPath := filepath.Join(path, "makeself.sh")
	// 获取makeself-header.sh文件路径
	makeSelfHeaderPath := filepath.Join(path, "makeself-header.sh")

	// 打印提示信息
	cl.PrintSuccess("检查系统环境...")

	// 检查是否是windows系统
	if runtime.GOOS == "windows" {
		return fmt.Errorf("makeself不支持windows系统, 请在linux系统上运行")
	}

	// 检查是否安装了makeself
	if path, err := exec.LookPath("makeself.sh"); err == nil {
		return fmt.Errorf("makeself已在系统中安装, 请先卸载 %s", path)
	}

	// 检查是否安装了makeself-header
	if path, err := exec.LookPath("makeself-header.sh"); err == nil {
		return fmt.Errorf("makeself-header已在系统中安装, 请先卸载 %s", path)
	}

	// 检查指定的路径是否存在
	if _, err := tools.CheckPath(path); err != nil {
		return fmt.Errorf("安装路径不存在: %s", err)
	}

	// 检查路径下是否已经存在makeself.sh文件
	if pathInfo, err := tools.CheckPath(makeSelfPath); err == nil {
		return fmt.Errorf("makeself.sh文件已存在, 请先删除 %s", pathInfo.Path)
	}

	// 检查路径下是否已经存在makeself-header.sh文件
	if pathInfo, err := tools.CheckPath(makeSelfHeaderPath); err == nil {
		return fmt.Errorf("makeself-header.sh文件已存在, 请先删除 %s", pathInfo.Path)
	}

	// 打印提示信息
	cl.PrintSuccess("开始安装makeself...")

	// 创建makeself.sh文件
	makeSelfFile, err := os.Create(makeSelfPath)
	if err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("创建makeself.sh文件失败: %s", err)
	}
	defer makeSelfFile.Close()

	// 写入makeself.sh文件内容
	if _, err := makeSelfFile.WriteString(makeselfTemplate); err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("写入makeself.sh文件失败: %s", err)
	}

	// 创建makeself-header.sh文件
	makeSelfHeaderFile, err := os.Create(makeSelfHeaderPath)
	if err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("创建makeself-header.sh文件失败: %s", err)
	}
	defer makeSelfHeaderFile.Close()

	// 写入makeself-header.sh文件内容
	if _, err := makeSelfHeaderFile.WriteString(makeselfHeaderTemplate); err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("写入makeself-header.sh文件失败: %s", err)
	}

	// 打印提示信息
	cl.PrintSuccess("正在设置makeself执行权限...")

	// 设置makeself.sh文件权限为可执行
	if err := os.Chmod(makeSelfPath, 0755); err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("设置makeself.sh文件权限失败: %s", err)
	}

	// 设置makeself-header.sh文件权限为可执行
	if err := os.Chmod(makeSelfHeaderPath, 0755); err != nil {
		// 清理生成的文件
		if err := cleanMakeself(makeSelfPath, makeSelfHeaderPath); err != nil {
			return fmt.Errorf("清理生成的文件失败: %s", err)
		}
		return fmt.Errorf("设置makeself-header.sh文件权限失败: %s", err)
	}

	// 打印提示信息
	cl.PrintSuccess("makeself安装完成")
	return nil
}

// 清理安装失败的makeself文件
func cleanMakeself(makeSelfPath, makeSelfHeaderPath string) error {
	// 打印提示信息
	cl.PrintInfof("开始清理makeself安装失败的文件...")

	// 检查makeself.sh文件是否存在
	if _, err := tools.CheckPath(makeSelfPath); err == nil {
		if err := os.Remove(makeSelfPath); err != nil {
			return fmt.Errorf("删除makeself.sh文件失败: %s", err)
		}
	}

	// 检查makeself-header.sh文件是否存在
	if _, err := tools.CheckPath(makeSelfHeaderPath); err == nil {
		if err := os.Remove(makeSelfHeaderPath); err != nil {
			return fmt.Errorf("删除makeself-header.sh文件失败: %s", err)
		}
	}

	cl.PrintSuccess("清理makeself安装失败的文件完成")

	return nil
}

// makeSelfPackage 函数用于打包自解压包
func makeSelfPackage(packIsNoTemp bool, packPackageDir, packRunPackageName, packUnZipMsg, packRunScript, packRunScriptArgs string) error {
	// 检查是否是windows系统
	if runtime.GOOS == "windows" {
		return fmt.Errorf("makeself不支持windows系统, 请在linux系统上运行")
	}

	// 检查是否已经安装makeself
	if _, err := exec.LookPath("makeself.sh"); err != nil {
		return fmt.Errorf("makeself未安装, 请先安装makeself")
	}

	// 检查是否已经安装makeself-header
	if _, err := exec.LookPath("makeself-header.sh"); err != nil {
		return fmt.Errorf("makeself-header未安装, 请先安装makeself-header")
	}

	// 检查是否设置了打包目录
	if _, err := tools.IsNotEmpty(packPackageDir, "打包目录"); err != nil {
		return fmt.Errorf("打包目录不能为空")
	}

	// 检查打包目录是否存在
	if _, err := tools.CheckPath(packPackageDir); err != nil {
		return fmt.Errorf("打包目录不存在: %s", packPackageDir)
	}

	// 检查是否设置了运行包名
	if _, err := tools.IsNotEmpty(packRunPackageName, "运行包名"); err != nil {
		return fmt.Errorf("运行包名不能为空, 例如: mypackage.run")
	}

	// 检查是否设置了解压信息
	if _, err := tools.IsNotEmpty(packUnZipMsg, "解压信息"); err != nil {
		return fmt.Errorf("解压信息不能为空")
	}

	// 检查是否设置了运行脚本
	if _, err := tools.IsNotEmpty(packRunScript, "运行脚本"); err != nil {
		return fmt.Errorf("运行脚本不能为空")
	}

	// 构建临时运行脚本路径
	tempScriptPath := fmt.Sprint(packPackageDir, "/", filepath.Base(packRunScript))

	// 检查运行脚本是否存在，获取运行脚本的权限检查是否为可执行
	if pathInfo, err := tools.CheckPath(tempScriptPath); err != nil {
		return fmt.Errorf("运行脚本不存在: %s", err)
	} else if !pathInfo.IsFile {
		return fmt.Errorf("运行脚本不是文件")
	} else if pathInfo.Mode&0111 == 0 {
		return fmt.Errorf("运行脚本权限不足, 请设置权限为可执行")
	}

	// 根据是否使用临时目录，构建打包命令
	var packCmd []string
	if packIsNoTemp {
		// 使用临时目录的格式：makeself.sh --notemp 打包目录 运行包名 解压信息 运行脚本 运行脚本参数
		packCmd = []string{"makeself.sh", "--notemp", packPackageDir, packRunPackageName, packUnZipMsg, packRunScript, packRunScriptArgs}
	} else {
		// 不使用临时目录的格式：makeself.sh 打包目录 运行包名 解压信息 运行脚本 运行脚本参数
		packCmd = []string{"makeself.sh", packPackageDir, packRunPackageName, packUnZipMsg, packRunScript, packRunScriptArgs}
	}

	// 执行打包命令
	if err := tools.ExecCmd(packCmd, "打包", false); err != nil {
		return fmt.Errorf("打包失败: %s", err)
	}

	// 打印提示信息
	cl.PrintSuccessf("打包完成, 运行包名: %s", packRunPackageName)

	return nil
}

// packCfgOrArgs 函数用于根据配置文件打包或根据命令行参数打包
func packCfgOrArgs(configPath string) error {
	// 如果指定了配置文件路径，则优先使用指定的配置文件
	if configPath != "" {
		if err := packWithConfig(configPath); err != nil {
			return fmt.Errorf("打包失败: %s", err)
		}

		return nil
	}

	// 如果未指定配置文件路径，尝试加载默认路径的配置文件
	if _, err := tools.CheckPath(defaultPackPath); err == nil {
		if err := packWithConfig(defaultPackPath); err != nil {
			return fmt.Errorf("打包失败: %s", err)
		}

		return nil
	}

	// 如果默认路径的配置文件也不存在，则通过命令行参数进行打包
	if err := packWithArgs(); err != nil {
		return fmt.Errorf("打包失败: %s", err)
	}

	return nil
}

// 根据配置文件打包
func packWithConfig(configPath string) error {
	// 读取配置文件
	configBytes, err := tools.ReadConfig(configPath)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %s", err)
	}

	// 解析配置文件
	var packConfig config.Config
	if err := yaml.Unmarshal(configBytes, &packConfig); err != nil {
		return fmt.Errorf("解析配置文件失败: %s", err)
	}

	// 将配置文件中的值赋值给命令行参数
	packIsNoTemp := packConfig.Pack.NoTemp              // 是否使用临时目录
	packPackageDir := packConfig.Pack.Dir               // 打包目录
	packRunPackageName := packConfig.Pack.OutputRunName // 运行包名
	packUnZipMsg := packConfig.Pack.UnZipMsg            // 解压信息
	packRunScript := packConfig.Pack.ScriptPath         // 运行脚本
	packRunScriptArgs := packConfig.Pack.Params         // 运行脚本参数

	// 构建解压信息
	packUnZipMsg = fmt.Sprintf(`"%s"`, packUnZipMsg)

	// 执行打包
	if err := makeSelfPackage(packIsNoTemp, packPackageDir, packRunPackageName, packUnZipMsg, packRunScript, packRunScriptArgs); err != nil {
		return err
	}

	// 返回
	return nil
}

// 根据命令行参数打包
func packWithArgs() error {
	// 合并 -dir 和 -d 选项的值
	packPackageDir, err := tools.MergeStringFlags(*tarPackageDirLong, *tarPackageDirShort) // 打包目录
	if err != nil {
		return fmt.Errorf("合并 -dir 和 -d 选项的值失败: %s", err)
	}

	// 合并 -name 和 -n 选项的值
	packRunPackageName, err := tools.MergeStringFlags(*runPackageNameLong, *runPackageNameShort) // run运行包名称
	if err != nil {
		return fmt.Errorf("合并 -name 和 -n 选项的值失败: %s", err)
	}

	// 合并 -msg 和 -m 选项的值
	packUnZipMsg, err := tools.MergeStringFlags(*unZipMsgLong, *unZipMsgShort) // 解压信息
	if err != nil {
		return fmt.Errorf("合并 -msg 和 -m 选项的值失败: %s", err)
	}
	// 构建解压信息
	packUnZipMsg = fmt.Sprintf(`"%s"`, packUnZipMsg)

	// 合并 -script 和 -s 选项的值
	packRunScript, err := tools.MergeStringFlags(*runScriptLong, *runScriptShort) // 运行脚本
	if err != nil {
		return fmt.Errorf("合并 -script 和 -s 选项的值失败: %s", err)
	}

	// 合并 -args 和 -a 选项的值
	packRunScriptArgs := *runScriptArgsLong
	if *runScriptArgsShort != "" {
		packRunScriptArgs = *runScriptArgsShort
	}

	// 执行打包
	if err := makeSelfPackage(*isNoTemp, packPackageDir, packRunPackageName, packUnZipMsg, packRunScript, packRunScriptArgs); err != nil {
		return err
	}

	return nil
}

// initBashStd 函数用于初始化标准版bash开发脚本
func initBashStd() error {
	// 初始化标准版bash开发脚本

	// 合并 -n 和 -name 选项的值
	initBashStdName, err := tools.MergeStringFlags(*initName, *initNameLong)
	if err != nil {
		return fmt.Errorf("合并 -n 和 -name 选项的值失败: %s", err)
	}

	// 检查是否设置了初始化名称
	if _, err := tools.IsNotEmpty(initBashStdName, "初始化名称"); err != nil {
		initBashStdName = "bash_std.sh"
	} else {
		// 检查初始化名称是否以.sh结尾
		if !strings.HasSuffix(initBashStdName, ".sh") {
			return fmt.Errorf("标准版脚本必须以.sh结尾")
		}

		// 检查初始化名称是否包含空格
		if strings.Contains(initBashStdName, " ") {
			return fmt.Errorf("初始化名称不能包含空格")
		}
	}

	// 检查当前目录下是否存在同名文件
	if _, err := os.Stat(initBashStdName); err == nil {
		return fmt.Errorf("当前目录下已存在同名文件, %s", initBashStdName)
	}

	// 检查提供的权限是否合法
	mode, err := tools.ConvertOctalStringToMode(*initPerm)
	if err != nil {
		return err
	}

	// 创建标准版bash开发脚本
	file, err := os.OpenFile(initBashStdName, os.O_CREATE|os.O_WRONLY, mode)
	if err != nil {
		return fmt.Errorf("创建标准版bash开发脚本失败: %s", err)
	}
	defer file.Close()

	// 写入标准版bash开发脚本内容
	file.WriteString(bashStdTemplate)

	// 打印成功信息
	cl.PrintSuccessf("创建标准版bash开发脚本成功: %s", initBashStdName)

	return nil
}

// initBashMin 函数用于初始化最小化版bash开发脚本
func initBashMin() error {
	// 初始化主版bash开发脚本

	// 合并 -n 和 -name 选项的值
	initBashMinName, err := tools.MergeStringFlags(*initName, *initNameLong)
	if err != nil {
		return fmt.Errorf("合并 -n 和 -name 选项的值失败: %s", err)
	}

	// 检查是否设置了初始化名称
	if _, err := tools.IsNotEmpty(initBashMinName, "初始化名称"); err != nil {
		initBashMinName = "bash_min.sh"
	} else {
		// 检查初始化名称是否以.sh结尾
		if !strings.HasSuffix(initBashMinName, ".sh") {
			return fmt.Errorf("最小化脚本必须以.sh结尾")
		}

		// 检查初始化名称是否包含空格
		if strings.Contains(initBashMinName, " ") {
			return fmt.Errorf("初始化名称不能包含空格")
		}
	}

	// 检查当前目录下是否存在同名文件
	if _, err := os.Stat(initBashMinName); err == nil {
		return fmt.Errorf("当前目录下已存在同名文件, %s", initBashMinName)
	}

	// 检查提供的权限是否合法
	mode, err := tools.ConvertOctalStringToMode(*initPerm)
	if err != nil {
		return err
	}

	// 创建最小化版bash开发脚本
	file, err := os.OpenFile(initBashMinName, os.O_CREATE|os.O_WRONLY, mode)
	if err != nil {
		return fmt.Errorf("创建最小化版bash开发脚本失败: %s", err)
	}
	defer file.Close()

	// 写入最小化版bash开发脚本内容
	file.WriteString(bashMinTemplate)

	// 打印成功信息
	cl.PrintSuccessf("创建最小化版bash开发脚本成功: %s", initBashMinName)

	return nil
}
